﻿using System;
using System.Collections.Generic;
using System.Linq;
using DLM.Domain.DTO;
using DLM.Domain.Model;
using DLM.Domain.Repositories;
using DLM.Infrastructure.Authentication;
using DLM.Infrastructure.Domain;
using DLM.Infrastructure.Email;
using DLM.Infrastructure.Exception;
using DLM.Infrastructure.Security;
using DLM.Infrastructure.UnitOfWork;
using DLM.Services.BonusRule;
using DLM.Services.Interfaces;
using DLM.Infrastructure.Logging;
using DLM.Infrastructure.Cache;
using DLM.Data.EF.CodeFirst.Repositories;

namespace DLM.Services.Implementations
{
    public class ScheduleService : IScheduleService
    {
        private IPartyRepository partyRepositroy;
        private IRemarkRepository remarkRepository;
        private IBonusLogRepository bonusLogRepository;
        private IBonusRepository bonusRepository;
        private IUserRepository userRepository;
        private IAccountRepositroy accountRepository;
        private IBonusCalculateStepRepository bonusCalculateRepository;


        public ScheduleService(IPartyRepository partyRepositroy,
            IRemarkRepository remarkRepository,
            IBonusLogRepository bonusLogRepository,
            IBonusRepository bonusRepository,
            IUserPartyAssociationRepository userPartyAssRepository,
            IUserRepository userRepository,
            IAccountRepositroy accountRepository,
            IBonusCalculateStepRepository bonusCalculateRepository)
        {
            this.partyRepositroy = partyRepositroy;
            this.remarkRepository = remarkRepository;
            this.bonusLogRepository = bonusLogRepository;
            this.bonusRepository = bonusRepository;
            this.userRepository = userRepository;
            this.accountRepository = accountRepository;
            this.bonusCalculateRepository = bonusCalculateRepository;
        }

        public void CloseParty()
        {


            var list = this.partyRepositroy.FindAll(p => p.Status == (int)PartyStatus.Freeze);

            var needClosedList = list.Where(p => p.EndDate <= DateTime.Now); 
            //list.Where(p => (DateTime.Now - p.EndDate).Days < 2);

            foreach (var item in needClosedList)
            {
                item.Status = (int)PartyStatus.Closed;
                var remarkList = this.remarkRepository.Where(r => r.PartyID == item.PartyID && r.Rate != 100);
                var count = remarkList.Count();
                var goodRemarkCount = remarkList.Count(r => r.Rate <=5);
                try 
                {
                  

                    float rate = 0;
                    if (goodRemarkCount > 0)
                    {
                        rate = goodRemarkCount / count;
                    }
                    
                    if (rate > 0.4)
                    {
                        item.IsSuccess = false;
                        this.partyRepositroy.Save(item);
                        ResetBonus(item.PartyID);
                        LoggingFactory.GetLogger().Log("Closed party, id is " + item.PartyID + " status is " + item.IsSuccess.ToString());
                    }
                    else
                    {
        
                        item.IsSuccess = true;
                        this.partyRepositroy.Save(item);
                        ModifyBonus(item.PartyID);
                        LoggingFactory.GetLogger().Log("Closed party, id is " + item.PartyID + " status is " + item.IsSuccess.ToString());
                    }

                    var allBillBoard = new PageDataRepository().BillboardList();
                    CacheHelper.SaveToCache<IEnumerable<BillBoard>>("AllBillBoard", allBillBoard);
                    var topBillBoard = new PageDataRepository().TopBillboardList();
                    CacheHelper.SaveToCache<IEnumerable<BillBoard>>("TopBillBoard", topBillBoard);
               
                }
                catch (Exception ex)
                {

                    LoggingFactory.GetLogger().Error(ex.Message, ex);
                }
     


            }

        }


        public void ModifyBonus(int partyID)
        {

            var list = this.userRepository.FindParticipatedDTO(partyID);
            BonusLog log = new BonusLog();
            foreach (var item in list)
            {
                var currentBonus = this.bonusRepository.FindByUser(item.UserID);
                if (item.IsLead == 1)
                {
                    IEnumerable<BonusCalculateStep> lastSteps = this.bonusCalculateRepository.FindByPartyAndUser(partyID, item.UserID)
                        .OrderByDescending(b => b.CreateDate);
                    //var tmp = lastSteps.Where(b => b.Step == "Engaged.Publish");

                    var temporaryStep = lastSteps.FirstOrDefault(b => b.Step == "TemporaryDistrain");
                    BonusCalculateStep tmpStep = new BonusCalculateStep();
                    tmpStep.PartyStatus = (int)PartyStatus.Closed;
                    tmpStep.IsSuccess = true;
                    tmpStep.PartyID = partyID;
                    tmpStep.UserID = item.UserID;
                    tmpStep.Step = "Engaged.Publish";
                    //tmpStep.OriginalBonus = temporaryStep.OriginalBonus + temporaryStep.Deduct;
                    tmpStep.Deduct = (BonusRuleFactory.GetBonusRuleService().Distrain.Engaged - BonusRuleFactory.GetBonusRuleService().TemporaryDistrain)
                        + BonusRuleFactory.GetBonusRuleService().Distrain.publish;
                    tmpStep.CreateDate = DateTime.Now;
                   
                    if (currentBonus.Bonuses.Value != (temporaryStep.OriginalBonus + temporaryStep.Deduct))
                    {
                        tmpStep.OriginalBonus = currentBonus.Bonuses.Value + temporaryStep.Deduct;
                        currentBonus.Bonuses = currentBonus.Bonuses + tmpStep.Deduct;
                    }
                    else
                    {
                        tmpStep.OriginalBonus = temporaryStep.OriginalBonus + temporaryStep.Deduct;
                        currentBonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }

                    this.bonusCalculateRepository.Add(tmpStep);

                    log.Bonus = tmpStep.Deduct;

                }
                else
                {

                    IEnumerable<BonusCalculateStep> lastSteps = this.bonusCalculateRepository.FindByPartyAndUser(partyID, item.UserID)
                        .OrderByDescending(b => b.CreateDate);

                    var temporaryStep = lastSteps.FirstOrDefault(b => b.Step == "TemporaryDistrain");
                    BonusCalculateStep tmpStep = new BonusCalculateStep();
                    tmpStep.PartyStatus = (int)PartyStatus.Closed;
                    tmpStep.IsSuccess = true;
                    tmpStep.PartyID = partyID;
                    tmpStep.UserID = item.UserID;
                    tmpStep.Step = "Engaged";
                   
                    tmpStep.Deduct = (BonusRuleFactory.GetBonusRuleService().Distrain.Engaged - BonusRuleFactory.GetBonusRuleService().TemporaryDistrain);
                    tmpStep.CreateDate = DateTime.Now;
                   

                    if (currentBonus.Bonuses.Value != (temporaryStep.OriginalBonus + temporaryStep.Deduct))
                    {
                        tmpStep.OriginalBonus = currentBonus.Bonuses.Value + temporaryStep.Deduct;
                        currentBonus.Bonuses = currentBonus.Bonuses + tmpStep.Deduct;
                    }
                    else
                    {
                        tmpStep.OriginalBonus = temporaryStep.OriginalBonus + temporaryStep.Deduct;
                        currentBonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }

                    this.bonusCalculateRepository.Add(tmpStep);

                    log.Bonus = tmpStep.Deduct;
                }
                
                this.bonusRepository.Save(currentBonus);

                log.CreateDate = DateTime.Now;
                log.PartyID = partyID;
                log.UserID = item.UserID;
                log.Desc = "活动成功结束，退还暂扣积分";
                this.bonusLogRepository.Add(log);
                LoggingFactory.GetLogger().Log("Calculate bonus for user id is " + log.UserID + " bonus is " + log.Bonus.Value.ToString());
            }
        }

        public void ResetBonus(int partyID)
        {
   
            var list = this.userRepository.FindParticipatedDTO(partyID);
            foreach (var item in list)
            {
                
                var currentBonus = this.bonusRepository.FindByUser(item.UserID);

                // Calculate fro temp step
                IEnumerable<BonusCalculateStep> lastSteps = this.bonusCalculateRepository.FindByPartyAndUser(partyID, item.UserID)
                    .OrderByDescending(b=>b.CreateDate);

                var closedAndSuccessStep = lastSteps.FirstOrDefault(b => b.Step == "Engaged.Publish" || b.Step == "Engaged");

                var temporaryStep = lastSteps.FirstOrDefault(b => b.Step == "TemporaryDistrain");
                BonusCalculateStep tmpStep = new BonusCalculateStep();
                tmpStep.PartyStatus = (int)PartyStatus.Closed;
                tmpStep.IsSuccess = false;
                tmpStep.PartyID = partyID;
                tmpStep.UserID = item.UserID;
                tmpStep.Step = "Reset";
                
                tmpStep.Deduct = -(BonusRuleFactory.GetBonusRuleService().TemporaryDistrain);
                tmpStep.CreateDate = DateTime.Now;

                if (closedAndSuccessStep != null)
                {
                    if (currentBonus.Bonuses.Value != (closedAndSuccessStep.OriginalBonus + closedAndSuccessStep.Deduct))
                    {
                        tmpStep.OriginalBonus = currentBonus.Bonuses.Value + temporaryStep.Deduct;
                        currentBonus.Bonuses = currentBonus.Bonuses.Value + tmpStep.Deduct;
                    }
                    else
                    {
                        tmpStep.OriginalBonus = temporaryStep.OriginalBonus + temporaryStep.Deduct;
                        currentBonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }
                }
                else
                {
                    if (currentBonus.Bonuses.Value != (temporaryStep.OriginalBonus + temporaryStep.Deduct))
                    {
                        tmpStep.OriginalBonus = currentBonus.Bonuses.Value + temporaryStep.Deduct;
                        currentBonus.Bonuses = currentBonus.Bonuses.Value + tmpStep.Deduct;
                    }
                    else
                    {
                        tmpStep.OriginalBonus = temporaryStep.OriginalBonus + temporaryStep.Deduct;
                        currentBonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }
                }
        
                this.bonusCalculateRepository.Add(tmpStep);


                // Calculate bonus
            
                this.bonusRepository.Save(currentBonus);

                // Add log
                BonusLog log = new BonusLog();
                log.Bonus = tmpStep.Deduct;
                log.CreateDate = DateTime.Now;
                log.PartyID = partyID;
                log.UserID = item.UserID;
                log.Desc = "活动以失败结束，退还积分";
                this.bonusLogRepository.Add(log);
                LoggingFactory.GetLogger().Log("Reset bonus for user id is " + log.UserID + " bonus is " + log.Bonus.Value.ToString());
            }
        }




        public void ValidateAccount()
        {
            var list = this.partyRepositroy.Statistics();
            foreach (var item in list)
            {
                float rate = ((item.EngagedCount - item.BreakAppCount) + 2) / item.EngagedCount;
                //float rate = (item.BreakAppCount + 2) / item.EngagedCount;
                if (rate <= 0.6)
                {
                    var user = this.userRepository.FindBy(item.UserID);
                    var account = this.accountRepository.FindBy(user.AccountID);
                    user.IsValidation = false;
                    account.IsValidation = false;
                    this.userRepository.Save(user);
                    this.accountRepository.Save(account);
                    LoggingFactory.GetLogger().Log("Validate account, account name is " + account.AccountName);
                }
            }
        }
    }
}
